package grape.common.service.trans;

import cn.hutool.core.annotation.AnnotationUtil;
import cn.hutool.core.lang.SimpleCache;
import cn.hutool.core.util.ReflectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import grape.common.service.trans.enhance.ITransEnhance;
import grape.common.service.trans.enhance.TransEnhanceMeta;
import grape.common.tools.ToolService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Field;
import java.util.List;

/**
 * Created by yangwei
 * Created at 2019/11/25 10:35
 */
@Component
@Slf4j
public class TransHelper implements ToolService {


    /**
     * 注解缓存
     */
    private static final SimpleCache<String, Annotation> ANNOTATION_CACHE = new SimpleCache<>();
    private static final SimpleCache<String, ITransService> TRANS_SERVICE_CACHE = new SimpleCache<>();

    @Autowired(required = false)
    private List<ITransService<?,?>> transServices;

    /**
     * 翻译入口
     * @param body
     */
    public Object trans(Object body){
        if (body == null) {
            return body;
        }
        long start = System.currentTimeMillis();
        log.debug("翻译开始:bodyClass=[{}]",body.getClass().getName());
        // 翻译支持
        if (!isEmpty(transServices)){
            if (body instanceof IPage) {
                List records = ((IPage) body).getRecords();
                if (!isEmpty(records)) {
                    for (Object record : records) {
                        transPojo(record);
                    }
                }
            }else if(body instanceof List) {
                ((List) body).forEach(item->{
                    transPojo(item);
                });

            }else{
                transPojo(body);
            }
        }
        log.debug("翻译结束:duration=[{}]ms",System.currentTimeMillis() - start);
        return body;
    }
    private void transPojo(Object body){
        // 还可以添加一个TransPower注解用在需要翻译的类上，来标识该类的属性是否需要翻译，来加速性能，暂时未实现
        // 只翻译vo实体
        if (body == null) {
            return;
        }
        Class<?> bodyClass = body.getClass();
        if(body instanceof ITransEnhance){
            List<TransEnhanceMeta> meta = ((ITransEnhance) body).getMeta();
            doTrans(meta,((ITransEnhance) body));
            List<Object> objects = ((ITransEnhance) body).transFieldValue();
            if (!isEmpty(objects)) {
                for (Object object : objects) {
                    trans(object);
                }
            }
        }else{

            handleTransAnnotion(body);
            handleTransItemAnnotion(body);
            for (Field field : ReflectUtil.getFields(bodyClass)) {
                // 翻译字段本身
                TransField transField = getAnnotation(field, TransField.class);
                if(transField != null){
                    trans(ReflectUtil.getFieldValue(body, field));
                }
                handleTransByAnnotion(field, body);
                handleTransForAnnotion(field, body);
            }
        }

    }
    /**
     * trans 支持
     * @param body
     */
    private void handleTransAnnotion(Object body){
        Trans trans = getAnnotation(body.getClass(), Trans.class);
        if (trans != null) {
            if(trans.value() != null){
                for (TransItem transItem : trans.value()) {
                    doTrans(transItem.type(), transItem.byFieldName(),transItem.forFieldName(), body);
                }
            }
        }
    }

    /**
     * transItem 支持
     * @param body
     */
    private void handleTransItemAnnotion(Object body){
        TransItem transItem = getAnnotation(body.getClass(), TransItem.class);
        if (transItem != null) {
            doTrans(transItem.type(), transItem.byFieldName(),transItem.forFieldName(), body);
        }
    }

    /**
     * TransBy 支持
     * @param field
     * @param body
     */
    private void handleTransByAnnotion(Field field, Object body){
        TransBy transBy = getAnnotation(field, TransBy.class);
        if (transBy != null) {
            doTrans(transBy.type(), transBy.byFieldName(),field.getName(), body);
        }
    }

    /**
     * transFor 支持
     * @param field
     * @param body
     */
    private void handleTransForAnnotion(Field field, Object body){
        TransFor transFor = getAnnotation(field, TransFor.class);
        if (transFor != null) {
            doTrans(transFor.type(), field.getName(), transFor.forFieldName(), body);
        }
    }

    private void doTrans(List<TransEnhanceMeta> meta,ITransEnhance enhance){
        if(isEmpty(meta)){
            return;
        }
        long start = System.currentTimeMillis();
        if(!isEmpty(transServices)){
            for (TransEnhanceMeta transEnhanceMeta : meta) {
                ITransService iTransServiceByType = getITransServiceByType(transEnhanceMeta.getType());
                if (iTransServiceByType != null) {
                    Object fieldValue = transEnhanceMeta.getByFieldValue();
                    if (fieldValue != null) {
                        Object transValue = iTransServiceByType.trans(transEnhanceMeta.getType(),fieldValue);
                        transEnhanceMeta.setTransValue(transValue);
                    }
                    continue;
                }
            }
        }

        enhance.resultMeta(meta);
        log.debug("dotrans duration=[{}]ms",System.currentTimeMillis() - start);
    }
    private void doTrans(String type,String currentFieldName,String targetFieldName,Object body){
        ITransService iTransServiceByType = getITransServiceByType(type);
        if (iTransServiceByType != null) {
            Object fieldValue = ReflectUtil.getFieldValue(body, currentFieldName);
            if (fieldValue != null) {
                Object transValue = iTransServiceByType.trans(type,fieldValue);
                ReflectUtil.setFieldValue(body,targetFieldName,transValue);
            }else {
                log.debug("全局翻译doTrans未获取到值,class=[{}],fieldName=[{}]",
                        body.getClass().getName(),currentFieldName);
            }
            return;
        }
    }

    private ITransService getITransServiceByType(String type){
        ITransService iTransService = TRANS_SERVICE_CACHE.get(type);
        if (iTransService != null) {
            return iTransService;
        }
        if(!isEmpty(transServices)){
            iTransService = transServices.stream().filter(iTransServiceItem -> iTransServiceItem.support(type)).findFirst().orElse(null);
            return TRANS_SERVICE_CACHE.put(type, iTransService);
        }
        return null;
    }
    private  <A extends Annotation> A getAnnotation(AnnotatedElement field, Class<A> annotationType){
        String key = null;
        if (field instanceof Field) {
            key = ((Field) field).getDeclaringClass().getName() + ((Field) field).getName();
        }else if(field instanceof Class) {
            key = ((Class) field).getName() ;
        }else {
            key = field.getClass() + field.toString();
        }
        key += annotationType.getName();
        A a = (A) ANNOTATION_CACHE.get(key);
        if (a != null) {
            return a;
        }
        a = AnnotationUtil.getAnnotation(field, annotationType);
        return (A) ANNOTATION_CACHE.put(key,a);
    }
}
